'use strict';
const path = require('path')
const pkgDir = require('pkg-dir').sync
const fse = require('fs-extra')
const npminstall = require('npminstall')
const pathExists = require('path-exists').sync

const { isObject } = require('@ting-cli-dev/utils')
const formatPath = require('@ting-cli-dev/format-path')
const { getDefaultRegistry,
        getNpmLatestVersion } = require('@ting-cli-dev/get-npm-info')


class Package {
    constructor(options) {
        if (!options) {
            throw new Error('Package类的options参数不能为空！')
        }
        if (!isObject(options)) {
            throw new Error('Package类的options必须是个对象！')
        }
        // package 目标路径
        this.targetPath = options.targetPath
        // package 存储缓存路径
        this.storeDir = options.storeDir
        // package 的 name
        this.packageName = options.packageName
        // package 的 version
        this.packageVersion = options.packageVersion

        // package的缓存目录前缀
        this.cacheFilePathPrefix = this.packageName.replace('/', '_')
        this.cacheFilePathGroup = this.packageName.split('/')[0]

    }

    get cacheFilePath() {
        // 根据缓存目录 + 实际缓存包的名字  推导而来的缓存路径
        return path.resolve(this.storeDir, `_${this.cacheFilePathPrefix}@${this.packageVersion}@${this.cacheFilePathGroup}`)
    }

    getNpmCacheFilePathByVersion(version) {
        return path.resolve(this.storeDir, `_${this.cacheFilePathPrefix}@${version}@${this.cacheFilePathGroup}`)  
        
    }

    async prepare() {
        // 如果缓存目录不存在就创建缓存目录
        if (this.storeDir && pathExists(this.storeDir)) {
            fse.mkdirpSync(this.storeDir)
        }

        // 获取 npm 包的最新版本号
        if (this.packageVersion === 'latest') {
            this.packageVersion = await getNpmLatestVersion(this.packageName)
        }
    }

    // 判断当前 package 是否存在
    async exists() {
        if (this.storeDir) {
            await this.prepare()
            console.log('cacheFilePath: ', this.cacheFilePath);
            return pathExists(this.cacheFilePath)
        } else {
            return pathExists(this.targetPath)
        }

    }

    // 安装 package
    async install() {
        await this.prepare()
        return npminstall({
            root: this.targetPath,
            // storeDir: root + 'node_modules',
            storeDir: this.storeDir,
            registry: getDefaultRegistry(),
            pkgs: [
                { name: this.packageName, version: this.packageVersion }
            ],
        })
    }

    

    // 更新 package
    async update() {
        await this.prepare()
        
        // 1. 获取 npm 罪最新版本号
        const latestNpmVersion = await getNpmLatestVersion(this.packageName)
        
        // 2. 查询最新版本号缓存路径是否存在
        const latestCacheFilePath = this.getNpmCacheFilePathByVersion(latestNpmVersion)

        // 3. 如果不存在，则直接安装最新版本
        if (pathExists(latestCacheFilePath)) {
            return null;
        } else {
            await npminstall({
                root: this.targetPath,
                // storeDir: root + 'node_modules',
                storeDir: this.storeDir,
                registry: getDefaultRegistry(),
                pkgs: [
                    { name: this.packageName, version: latestNpmVersion }
                ],
            })
            this.packageVersion = latestNpmVersion
        }
    }

    // 获得入口文件路径
    getRootFilePath() {
        function _getRootPath (targetPath) {
            // 1. 获取package.json 所在目录
            const dir = pkgDir(targetPath)
            // 2. 读取package.json - require
            if(dir) {
                // 3. 寻找main/lib
                const pkgFile = require(path.resolve(dir, 'package.json'))
                if(pkgFile && pkgFile.main){
                    // console.log(pkgFile);
                    // 4. 路径兼容(兼容 MacOS/windos)
                    return formatPath(path.resolve(dir ,pkgFile.main))
                }
                return null
                
            }
            return null
        }

        if(this.storeDir){
            return _getRootPath(this.cacheFilePath)
        }else {
            return _getRootPath(this.targetPath)
        }
    }
}

module.exports = Package;
